Design Patterns - Command Pattern

example-observer-design-pattern

Intent

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

command-pattern-uml

The Client is responsible for creating a Concrete Command and setting it’s receiver. The command object consists of a set of actions on a receiver.

The Receiver knows how to perform the work needed to carry out the request. Any class can act as Receiver.

Command interface declares an interface for all commands. Command is invoked through its execute() method, which asks for a receiver to perform an action.

The Concrete Command defines a binding between an action and a receiver. The invoker makes a request by calling execute() and the ConcreteCommand carries it out by calling one or more actions on the Receiver.

Summary

  • The Command Pattern decouples an object making a request from the one that knows how to perform it.
  • A command object is at the center of this decoupling and encapsulates a receiver with an action (or set of actions).
  • An invoker makes a request of a Command object by calling its execute() method, which invokes those actions on the receiver.
  • Invoker can be parameterized with Commands, even dynamically at runtime.
  • Commands may support undo by implementing an undo method that restores the object to its previous state before the execute() method was last called.

Example

command-pattern-uml

package com.art.head_first.homeautomation;
public interface Command {
void execute();
void undo();
}
view raw Command.java hosted with ❤ by GitHub
package com.art.head_first.homeautomation;
public class Light {
boolean isOn;
public void on(){
isOn = true;
System.out.println("Light is On");
}
public void off(){
isOn = false;
System.out.println("Light is Off");
}
}
view raw Light.java hosted with ❤ by GitHub
package com.art.head_first.homeautomation;
public class LightOffCommand implements Command{
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
@Override
public void undo() {
light.on();
}
}
package com.art.head_first.homeautomation;
public class LightOnCommand implements Command{
Light light;
@Override
public void execute() {
light.on();
}
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void undo() {
light.off();
}
}
package com.art.head_first.homeautomation;
public class SimpleRemoteControl {
Command slot;
public void setCommand(Command command){
slot = command;
}
public void pressButton(){
slot.execute();
}
public void undo(){
slot.undo();
}
}
package com.art.head_first.homeautomation;
/**
* Client Class is responsible for Creating Concrete Commands and setting it's receiver
*/
public class SimpleRemoteControlTest {
public static void main(String[] args) {
SimpleRemoteControl rc = new SimpleRemoteControl();
Light light = new Light();
Stereo stereo = new Stereo();
rc.setCommand(new LightOnCommand(light));
rc.pressButton();
rc.undo();
rc.setCommand(new StereoOnCommand(stereo));
rc.pressButton();
rc.undo();
rc.setCommand(new StereoOffCommand(stereo));
rc.pressButton();
rc.undo();
}
}
package com.art.head_first.homeautomation;
public class Stereo {
boolean isOn;
int volume;
public void on(){
this.isOn = true;
System.out.println("Stereo is On");
}
public void off(){
this.isOn = false;
System.out.println("Stereo is Off");
}
public void setVolume(int volume)
{
this.volume = volume;
System.out.println("Stereo Volume is set to: " + volume);
}
}
view raw Stereo.java hosted with ❤ by GitHub
package com.art.head_first.homeautomation;
public class StereoOffCommand implements Command{
Stereo stereo;
public StereoOffCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
stereo.off();
}
@Override
public void undo() {
stereo.on();
}
}
package com.art.head_first.homeautomation;
public class StereoOnCommand implements Command{
Stereo stereo;
public StereoOnCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
stereo.on();
}
@Override
public void undo() {
stereo.off();
}
}